Skip to content

[PowerPC][CodeGen] Expand ISD::AssertNoFPClass for ppc_fp128 #152357

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 13, 2025

Conversation

amy-kwan
Copy link
Contributor

@amy-kwan amy-kwan commented Aug 6, 2025

780054d added support for ISD::AssertNoFPClass.

This ISD node can be used with the ppc_fp128 type, which is really just two f64s and requires expanding when used with ISD::AssertNoFPClass. Without the support for expanding the result, we get an assertion because the legalizer does not know how to expand the results of ppc_fp128 with ISD::AssertNoFPClass.

ExpandFloatResult #0: t7: ppcf128 = AssertNoFPClass t5, TargetConstant:i32<3>

LLVM ERROR: Do not know how to expand the result of this operator!

Thus, this patch aims to add support for the expand so we no longer assert.

This fixes #151375.

@llvmbot
Copy link
Member

llvmbot commented Aug 6, 2025

@llvm/pr-subscribers-backend-powerpc

Author: Amy Kwan (amy-kwan)

Changes

780054d added support for ISD::AssertNoFPClass.

This ISD node can be used with the ppc_fp128 type, which is really just two f64s and requires expanding when used with ISD::AssertNoFPClass. Without the support for expanding the result, we get an assertion because the legalizer does not know how to expand the results of ppc_fp128 with ISD::AssertNoFPClass.

ExpandFloatResult #<!-- -->0: t7: ppcf128 = AssertNoFPClass t5, TargetConstant:i32&lt;3&gt;

LLVM ERROR: Do not know how to expand the result of this operator!

Thus, this patch aims to add support for the expand so we no longer assert.

This fixes #151375.


Full diff: https://github.com/llvm/llvm-project/pull/152357.diff

3 Files Affected:

  • (modified) llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp (+9)
  • (modified) llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h (+1)
  • (added) llvm/test/CodeGen/PowerPC/nofpclass.ll (+13)
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
index 2cad36eff9c88..8140c0e771a7b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -1551,6 +1551,7 @@ void DAGTypeLegalizer::ExpandFloatResult(SDNode *N, unsigned ResNo) {
   case ISD::VAARG:              ExpandRes_VAARG(N, Lo, Hi); break;
 
   case ISD::ConstantFP: ExpandFloatRes_ConstantFP(N, Lo, Hi); break;
+  case ISD::AssertNoFPClass: ExpandFloatRes_AssertNoFPClass(N, Lo, Hi); break;
   case ISD::FABS:       ExpandFloatRes_FABS(N, Lo, Hi); break;
   case ISD::STRICT_FMINNUM:
   case ISD::FMINNUM:    ExpandFloatRes_FMINNUM(N, Lo, Hi); break;
@@ -1966,6 +1967,14 @@ void DAGTypeLegalizer::ExpandFloatRes_FNEG(SDNode *N, SDValue &Lo,
   Hi = DAG.getNode(ISD::FNEG, dl, Hi.getValueType(), Hi);
 }
 
+void DAGTypeLegalizer::ExpandFloatRes_AssertNoFPClass(SDNode *N, SDValue &Lo,
+                                                      SDValue &Hi) {
+  SDLoc dl(N);
+  GetExpandedFloat(N->getOperand(0), Lo, Hi);
+  Lo = DAG.getNode(ISD::AssertNoFPClass, dl, Lo.getValueType(), Lo);
+  Hi = DAG.getNode(ISD::AssertNoFPClass, dl, Hi.getValueType(), Hi);
+}
+
 void DAGTypeLegalizer::ExpandFloatRes_FP_EXTEND(SDNode *N, SDValue &Lo,
                                                 SDValue &Hi) {
   EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
index 63544e63e1da1..33fa3012618b3 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
@@ -681,6 +681,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
       SDNode *N, RTLIB::Libcall LC, std::optional<unsigned> CallRetResNo = {});
 
   // clang-format off
+  void ExpandFloatRes_AssertNoFPClass(SDNode *N, SDValue &Lo, SDValue &Hi);
   void ExpandFloatRes_FABS      (SDNode *N, SDValue &Lo, SDValue &Hi);
   void ExpandFloatRes_FACOS     (SDNode *N, SDValue &Lo, SDValue &Hi);
   void ExpandFloatRes_FASIN     (SDNode *N, SDValue &Lo, SDValue &Hi);
diff --git a/llvm/test/CodeGen/PowerPC/nofpclass.ll b/llvm/test/CodeGen/PowerPC/nofpclass.ll
new file mode 100644
index 0000000000000..444e62cbbcffc
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/nofpclass.ll
@@ -0,0 +1,13 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -verify-machineinstrs  -mtriple=powerpc64le-unknown-linux-gnu < %s \
+; RUN:   | FileCheck %s
+; RUN: llc -verify-machineinstrs  -mtriple=powerpc64-ibm-aix-xcoff < %s \
+; RUN:   | FileCheck %s
+
+define ppc_fp128 @f(ppc_fp128 nofpclass(nan) %s) {
+; CHECK-LABEL: f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    blr
+entry:
+  ret ppc_fp128 %s
+}

@llvmbot
Copy link
Member

llvmbot commented Aug 6, 2025

@llvm/pr-subscribers-llvm-selectiondag

Author: Amy Kwan (amy-kwan)

Changes

780054d added support for ISD::AssertNoFPClass.

This ISD node can be used with the ppc_fp128 type, which is really just two f64s and requires expanding when used with ISD::AssertNoFPClass. Without the support for expanding the result, we get an assertion because the legalizer does not know how to expand the results of ppc_fp128 with ISD::AssertNoFPClass.

ExpandFloatResult #<!-- -->0: t7: ppcf128 = AssertNoFPClass t5, TargetConstant:i32&lt;3&gt;

LLVM ERROR: Do not know how to expand the result of this operator!

Thus, this patch aims to add support for the expand so we no longer assert.

This fixes #151375.


Full diff: https://github.com/llvm/llvm-project/pull/152357.diff

3 Files Affected:

  • (modified) llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp (+9)
  • (modified) llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h (+1)
  • (added) llvm/test/CodeGen/PowerPC/nofpclass.ll (+13)
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
index 2cad36eff9c88..8140c0e771a7b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -1551,6 +1551,7 @@ void DAGTypeLegalizer::ExpandFloatResult(SDNode *N, unsigned ResNo) {
   case ISD::VAARG:              ExpandRes_VAARG(N, Lo, Hi); break;
 
   case ISD::ConstantFP: ExpandFloatRes_ConstantFP(N, Lo, Hi); break;
+  case ISD::AssertNoFPClass: ExpandFloatRes_AssertNoFPClass(N, Lo, Hi); break;
   case ISD::FABS:       ExpandFloatRes_FABS(N, Lo, Hi); break;
   case ISD::STRICT_FMINNUM:
   case ISD::FMINNUM:    ExpandFloatRes_FMINNUM(N, Lo, Hi); break;
@@ -1966,6 +1967,14 @@ void DAGTypeLegalizer::ExpandFloatRes_FNEG(SDNode *N, SDValue &Lo,
   Hi = DAG.getNode(ISD::FNEG, dl, Hi.getValueType(), Hi);
 }
 
+void DAGTypeLegalizer::ExpandFloatRes_AssertNoFPClass(SDNode *N, SDValue &Lo,
+                                                      SDValue &Hi) {
+  SDLoc dl(N);
+  GetExpandedFloat(N->getOperand(0), Lo, Hi);
+  Lo = DAG.getNode(ISD::AssertNoFPClass, dl, Lo.getValueType(), Lo);
+  Hi = DAG.getNode(ISD::AssertNoFPClass, dl, Hi.getValueType(), Hi);
+}
+
 void DAGTypeLegalizer::ExpandFloatRes_FP_EXTEND(SDNode *N, SDValue &Lo,
                                                 SDValue &Hi) {
   EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0));
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
index 63544e63e1da1..33fa3012618b3 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
@@ -681,6 +681,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
       SDNode *N, RTLIB::Libcall LC, std::optional<unsigned> CallRetResNo = {});
 
   // clang-format off
+  void ExpandFloatRes_AssertNoFPClass(SDNode *N, SDValue &Lo, SDValue &Hi);
   void ExpandFloatRes_FABS      (SDNode *N, SDValue &Lo, SDValue &Hi);
   void ExpandFloatRes_FACOS     (SDNode *N, SDValue &Lo, SDValue &Hi);
   void ExpandFloatRes_FASIN     (SDNode *N, SDValue &Lo, SDValue &Hi);
diff --git a/llvm/test/CodeGen/PowerPC/nofpclass.ll b/llvm/test/CodeGen/PowerPC/nofpclass.ll
new file mode 100644
index 0000000000000..444e62cbbcffc
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/nofpclass.ll
@@ -0,0 +1,13 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -verify-machineinstrs  -mtriple=powerpc64le-unknown-linux-gnu < %s \
+; RUN:   | FileCheck %s
+; RUN: llc -verify-machineinstrs  -mtriple=powerpc64-ibm-aix-xcoff < %s \
+; RUN:   | FileCheck %s
+
+define ppc_fp128 @f(ppc_fp128 nofpclass(nan) %s) {
+; CHECK-LABEL: f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    blr
+entry:
+  ret ppc_fp128 %s
+}

Comment on lines 1974 to 1975
Lo = DAG.getNode(ISD::AssertNoFPClass, dl, Lo.getValueType(), Lo);
Hi = DAG.getNode(ISD::AssertNoFPClass, dl, Hi.getValueType(), Hi);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it's safe to directly take the value for both halves, and if it is it's only in double double cases like ppcf128. For ppcf128, it might not even apply to both halves. The safest option to get the compilation to stop failing is to drop the operation altogether and revisit the details of when it's preservable later

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at PPCTargetLowering::LowerIS_FPCLASS, it appears that for ppcf128 the class is determined by element 1. So I think propagating the info for element 1 is correct. I don't have any evidence about element 0, so I think it should not be propagated there. I am okay with not propagating the assert for both elements for now. I don't see any type tests or asserts so it's hard to be confident that only ppcf128 reaches here, so I think ppcf128 specific stuff like element 1 is class should be if protected and there be a general clear both path.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yeah, I noticed I have a typo here.

As Roland mentioned, the class comes from the first element, which is what I meant:

SDValue PPCTargetLowering::LowerIS_FPCLASS(SDValue Op,
                                           SelectionDAG &DAG) const {
  assert(Subtarget.hasP9Vector() && "Test data class requires Power9");
  SDValue LHS = Op.getOperand(0);
  uint64_t RHSC = Op.getConstantOperandVal(1);
  SDLoc Dl(Op);
  FPClassTest Category = static_cast<FPClassTest>(RHSC);
  if (LHS.getValueType() == MVT::ppcf128) {
    // The higher part determines the value class.
    LHS = DAG.getNode(ISD::EXTRACT_ELEMENT, Dl, MVT::f64, LHS,
                      DAG.getConstant(1, Dl, MVT::i32));
  }

  return getDataClassTest(LHS, Category, Dl, DAG, Subtarget);
}

Unless I am misunderstanding, based on the two comments, propagating the information from element 1 is correct but it sounds like should just drop the operation for now.

@arsenm Dumb question, sorry - but what exactly does dropping the operation look like in this case? I assume the Hi and Lo would not be set then?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing through the results of GetExpandedFloat directly to the final results, without constructing a new AssertNoFPClass

Comment on lines 2 to 5
; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu < %s \
; RUN: | FileCheck %s
; RUN: llc -verify-machineinstrs -mtriple=powerpc64-ibm-aix-xcoff < %s \
; RUN: | FileCheck %s
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu < %s \
; RUN: | FileCheck %s
; RUN: llc -verify-machineinstrs -mtriple=powerpc64-ibm-aix-xcoff < %s \
; RUN: | FileCheck %s
; RUN: llc -mtriple=powerpc64le-unknown-linux-gnu < %s | FileCheck %s
; RUN: llc -mtriple=powerpc64-ibm-aix-xcoff < %s | FileCheck %s

; CHECK-NEXT: blr
entry:
ret ppc_fp128 %s
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally would test with more masks, and some cases that demonstrate downstream effects of preserving it after legalization. That's best left to a follow up that tries to preserve it though

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could be misunderstanding, but do you mean we are OK with updating the test in a follow up patch if we do decide not to drop the AssertNoFPClass when expanding?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, a later patch which doesn't drop the assert would need more tests.

This is the minimal test which shows the legalization doesn't crash, but this doesn't show it's being preserved. You'd need some optimization that triggers on the type legalized dag, not sure what that would look like in the ppc case

@arsenm arsenm requested a review from jcranmer-intel August 7, 2025 00:03
Comment on lines 1974 to 1975
Lo = DAG.getNode(ISD::AssertNoFPClass, dl, Lo.getValueType(), Lo);
Hi = DAG.getNode(ISD::AssertNoFPClass, dl, Hi.getValueType(), Hi);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing through the results of GetExpandedFloat directly to the final results, without constructing a new AssertNoFPClass

SDValue &Hi) {
SDLoc dl(N);
GetExpandedFloat(N->getOperand(0), Lo, Hi);
Lo = DAG.getNode(ISD::AssertNoFPClass, dl, Lo.getValueType(), Lo);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Lo = DAG.getNode(ISD::AssertNoFPClass, dl, Lo.getValueType(), Lo);

@amy-kwan amy-kwan force-pushed the amy-kwan/ppc-nofpclass branch from 56854a1 to c2ae546 Compare August 12, 2025 14:55
@amy-kwan amy-kwan requested a review from arsenm August 12, 2025 14:56
void DAGTypeLegalizer::ExpandFloatRes_AssertNoFPClass(SDNode *N, SDValue &Lo,
SDValue &Hi) {
SDLoc dl(N);
GetExpandedFloat(N->getOperand(0), Lo, Hi);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add todo to preserve it for the half for ppcf128 if you aren't going to immediately follow up with that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, I've added the TODO here and in the test.

; CHECK-NEXT: blr
entry:
ret ppc_fp128 %s
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, a later patch which doesn't drop the assert would need more tests.

This is the minimal test which shows the legalization doesn't crash, but this doesn't show it's being preserved. You'd need some optimization that triggers on the type legalized dag, not sure what that would look like in the ppc case

780054d added support for `ISD::AssertNoFPClass`.

This ISD node can be used with the `ppc_fp128` type, which is really just two
`f64s` and requires expanding when used with `ISD::AssertNoFPClass`. Without the
support for expanding the result, we get an assertion because the legalizer
does not know how to expand the results of `ppc_fp128` with `ISD::AssertNoFPClass`.
```
ExpandFloatResult #0: t7: ppcf128 = AssertNoFPClass t5, TargetConstant:i32<3>

LLVM ERROR: Do not know how to expand the result of this operator!
```
Thus, this patch aims to add support for the expand so we no longer assert.

This fixes llvm#151375.
@amy-kwan amy-kwan force-pushed the amy-kwan/ppc-nofpclass branch from 388fce6 to 0362e0d Compare August 13, 2025 14:20
@amy-kwan amy-kwan added this to the LLVM 21.x Release milestone Aug 13, 2025
@github-project-automation github-project-automation bot moved this to Needs Triage in LLVM Release Status Aug 13, 2025
@amy-kwan amy-kwan merged commit 63cc2e3 into llvm:main Aug 13, 2025
9 checks passed
@github-project-automation github-project-automation bot moved this from Needs Triage to Done in LLVM Release Status Aug 13, 2025
@amy-kwan
Copy link
Contributor Author

/cherry-pick 63cc2e3

@llvm-ci
Copy link
Collaborator

llvm-ci commented Aug 13, 2025

LLVM Buildbot has detected a new failure on builder ml-opt-dev-x86-64 running on ml-opt-dev-x86-64-b1 while building llvm at step 6 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/137/builds/23502

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'LLVM :: CodeGen/Thumb2/mve-vcvt-fixed-to-float.ll' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
/b/ml-opt-dev-x86-64-b1/build/bin/llc -mtriple=thumbv8.1m.main-arm-none-eabi /b/ml-opt-dev-x86-64-b1/llvm-project/llvm/test/CodeGen/Thumb2/mve-vcvt-fixed-to-float.ll -o - -mattr=+mve.fp | /b/ml-opt-dev-x86-64-b1/build/bin/FileCheck /b/ml-opt-dev-x86-64-b1/llvm-project/llvm/test/CodeGen/Thumb2/mve-vcvt-fixed-to-float.ll # RUN: at line 2
+ /b/ml-opt-dev-x86-64-b1/build/bin/llc -mtriple=thumbv8.1m.main-arm-none-eabi /b/ml-opt-dev-x86-64-b1/llvm-project/llvm/test/CodeGen/Thumb2/mve-vcvt-fixed-to-float.ll -o - -mattr=+mve.fp
+ /b/ml-opt-dev-x86-64-b1/build/bin/FileCheck /b/ml-opt-dev-x86-64-b1/llvm-project/llvm/test/CodeGen/Thumb2/mve-vcvt-fixed-to-float.ll
/b/ml-opt-dev-x86-64-b1/llvm-project/llvm/test/CodeGen/Thumb2/mve-vcvt-fixed-to-float.ll:479:15: error: CHECK-NEXT: expected string not found in input
; CHECK-NEXT: vmov.i16 q1, #0x200
              ^
<stdin>:691:9: note: scanning from here
@ %bb.0:
        ^
<stdin>:692:2: note: possible intended match here
 vcvt.f16.s16 q0, q0, #15
 ^
/b/ml-opt-dev-x86-64-b1/llvm-project/llvm/test/CodeGen/Thumb2/mve-vcvt-fixed-to-float.ll:965:15: error: CHECK-NEXT: expected string not found in input
; CHECK-NEXT: vmov.i16 q1, #0x200
              ^
<stdin>:1367:9: note: scanning from here
@ %bb.0:
        ^
<stdin>:1368:2: note: possible intended match here
 vcvt.f16.u16 q0, q0, #15
 ^

Input file: <stdin>
Check file: /b/ml-opt-dev-x86-64-b1/llvm-project/llvm/test/CodeGen/Thumb2/mve-vcvt-fixed-to-float.ll

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            .
            .
            .
          686:  .type vcvt_i16_15,%function 
          687:  .code 16 
          688:  .thumb_func 
          689: vcvt_i16_15: @ @vcvt_i16_15 
          690:  .fnstart 
          691: @ %bb.0: 
next:479'0             X error: no match found
          692:  vcvt.f16.s16 q0, q0, #15 
next:479'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~
next:479'1      ?                         possible intended match
          693:  bx lr 
next:479'0     ~~~~~~~
          694: .Lfunc_end47: 
...

@amy-kwan
Copy link
Contributor Author

LLVM Buildbot has detected a new failure on builder ml-opt-dev-x86-64 running on ml-opt-dev-x86-64-b1 while building llvm at step 6 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/137/builds/23502

Here is the relevant piece of the build log for the reference

I've reverted my change locally. This failure doesn't appear to be due to my change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:PowerPC llvm:SelectionDAG SelectionDAGISel as well
Projects
Development

Successfully merging this pull request may close these issues.

LLVM 21.1.0: Unable to expand result for ppcf128 with ISD::AssertNoFPClass
5 participants